package impl

import (
	"context"
	"fmt"
	"time"

	"gitee.com/shiwjlinux/arm/apps/host"
	"gitee.com/shiwjlinux/arm/apps/instance"
	"gitee.com/shiwjlinux/arm/common"
	"gitee.com/shiwjlinux/arm/exception"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
)

// CreateInstance 创建实例
func (i *Impl) CreateInstance(ctx context.Context,
	in *instance.Instance) (
	*instance.Instance, error,
) {
	if err := common.Validate(i); err != nil {
		return nil, err
	}
	// i.logger.Debug().Msgf("(i *Impl) CreateInstance request %+v ", in)

	// 查询主机信息
	queryHost := host.NewQueryHostRequest()
	queryHost.Sn = in.Sn

	hostSet, err := i.host.QueryHost(ctx, queryHost)
	if err != nil {
		return nil, err
	}

	// 如果没有查到主机信息，需要添加主机信息
	// if len(hostSet.Items) == 0 {
	// 	return nil, exception.ErrorNotFound
	// }

	var createHost *host.Host
	switch len(hostSet.Items) == 0 {
	// 没有主机信息 添加主机
	// 有信息 添加instance
	case true:
		i.logger.Debug().Msgf("(i *Impl) CreateInstance create host, sn %s", in.Sn)
		chr := host.NewCreateHostRequest(in.Sn, in.Hostname)
		createHost, err = i.host.CreateHost(ctx, chr)
		if err != nil {
			return nil, err
		}

	case false:
		i.logger.Debug().Msgf("(i *Impl) CreateInstance found host, sn %s", in.Sn)
		createHost = hostSet.Items[0]
	}
	in.Hostname = createHost.Hostname

	_, err = i.db.
		Collection(instance.AppName).
		UpdateOne(ctx,
			bson.M{"_id": in.ID},
			bson.M{"$set": in},
			options.Update().SetUpsert(true))
	if err != nil {
		return nil, exception.ErrorFailed
		// return nil, err
	}

	return in, nil
}

func (i *Impl) DeleteInstance(ctx context.Context,
	in *instance.DeleteInstanceRequest,
) (*instance.Instance, error) {
	_, err := i.db.
		Collection(instance.AppName).
		DeleteOne(ctx, bson.M{"_id": bson.M{"$in": in.IDs}})
	if err != nil {
		return nil, err
	}

	return nil, nil
}

func (i *Impl) DescribeInstance(ctx context.Context,
	in *instance.DescribeInstanceRequest,
) (ins *instance.Instance, err error) {
	err = i.db.
		Collection(instance.AppName).
		FindOne(ctx, bson.M{"_id": in.ID}).
		Decode(&ins)
	if err != nil {
		if err == mongo.ErrNoDocuments {
			return nil, nil // TODO: 返回一个自定义的错误，例如 "Instance not found"
		}
		return nil, err
	}

	return ins, nil
}

func (i *Impl) QueryInstance(ctx context.Context,
	in *instance.QueryInstanceRequest,
) (*instance.InstanceSet, error) {
	// set := instance.NewInstance()
	filter := bson.M{}

	if in.Keywords != "" {
		filter["name"] = bson.M{"$regex": in.Keywords, "$options": "im"}
	}

	// i.logger.Debug().Msgf("in %+v", in)
	if in.ID != "" {
		filter["_id"] = bson.M{"$regex": in.ID, "$options": "im"}
	}

	if in.Sn != "" {
		filter["sn"] = bson.M{"$regex": in.Sn, "$options": "im"}
	}

	for k, v := range in.Tags {
		filter["tags."+k] = v
	}
	opt := options.Find()
	opt.SetLimit(int64(in.PageSize))
	opt.SetSkip(int64(in.Offect()))
	cursor, err := i.db.Collection(instance.AppName).Find(ctx, filter, opt)
	if err != nil {
		return nil, err
	}

	set := instance.NewInstanceSet()

	for cursor.Next(ctx) {
		n := instance.NewInstance()
		if err := cursor.Decode(n); err != nil {
			return nil, err
		}
		set.Items = append(set.Items, n)
		set.Total += 1
	}

	return set, nil
}

func (i *Impl) UpdateHeartbeat(ctx context.Context,
	in *instance.UpdateHeartbeatRequest) (*instance.Instance, error) {

	ins, err := i.DescribeInstance(ctx, instance.NewDescribeInstanceRequest(in.ID))
	if err != nil {
		return nil, err
	}
	filter := bson.M{"_id": in.ID}
	update := bson.M{"$set": bson.M{
		"updated_at":        in.UpdatedAt,
		"server_updated_at": time.Now().Unix(), //每次自动更新时间戳
	}}
	result, err := i.db.Collection(instance.AppName).UpdateOne(ctx, filter, update)
	if err != nil {
		return nil, err
	}

	fmt.Println(result)

	return ins, nil
}

func (i *Impl) UpdateHeartbeats(ctx context.Context,
	in *instance.UpdateHeartbeatRequests) error {

	filter := bson.M{"_id": bson.M{"$in": in.IDs}}
	update := bson.M{"$set": bson.M{
		"updated_at":        in.UpdatedAt,
		"server_updated_at": time.Now().Unix(), //每次自动更新时间戳
	}}

	_, err := i.db.Collection(instance.AppName).UpdateMany(ctx, filter, update)
	if err != nil {
		return err
	}

	return nil
}
